#pragma once
#include<iostream>

using namespace std;

namespace bit {
	template<class T> 
	class auto_ptr {
	private:
		T* _ptr;
	public:
		auto_ptr(T* ptr=nullptr)
			:_ptr(ptr)
		{}
		~auto_ptr() {
			cout << "auto_ptr delete" << endl;
			delete _ptr;
		}	
		T& operator* () {
			return *_ptr;
		}
		T* operator->() {
			return _ptr;
		}
		auto_ptr(auto_ptr<T>& p)
			:_ptr(p._ptr)
		{
			p._ptr = nullptr;
		}
	};
	template<class T>
	class unique_ptr {
	private:
		T* _ptr;
	public:
		unique_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{}
		~unique_ptr() {
			cout << "unique_ptr delete" << endl;
			delete _ptr;
		}
		T& operator* () {
			return *_ptr;
		}
		T* operator->() {
			return _ptr;
		}
		unique_ptr(unique_ptr& p) = delete;
		unique_ptr& operator=(unique_ptr<T>& p) = delete;

	};
	template<class T>
	class shared_ptr {
	private:
		T* _ptr;
		int* _pcount;
	public:
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			,_pcount(new int(1))
		{}
		~shared_ptr() {
			cout << "shared_ptr delete" << endl;
			if (--(_pcount) == 0) {
				delete _ptr;
				delete _pcount;
			}
		}
		T& operator* () {
			return *_ptr;
		}
		T* operator->() {
			return _ptr;
		}
		shared_ptr(shared_ptr& p) 
			:_ptr(p._ptr)
			, _pcount(p._pcount)
		{
			*(_pcount)++;
		}
		shared_ptr& operator=(shared_ptr<T>& p) {
			if (_ptr == p._ptr)return *this;
			if (--(*_pcount) == 0) {
				delete _ptr;
				delete _pcount;
			}
			_ptr = p._ptr;
			_pcount = p._pcount;
			*(_pcount)++;
			return *this;
		}
		T* get() {
			return _ptr;
		}
	};
	template<class T>
	class weak_ptr {
	private:
		T* _ptr;
	public:
		weak_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{}
		~weak_ptr() {
			cout << "weak_ptr delete" << endl;
			delete _ptr;
		}
		T& operator* () {
			return *_ptr;
		}
		T* operator->() {
			return _ptr;
		}
		weak_ptr(shared_ptr<T>& p) 
			:_ptr(p.get())
		{}
		weak_ptr& operator=(shared_ptr<T>& p)
		{
			_ptr = p.get();
			return *this;
		}

	};
	


}